package clh;

import java.awt.Color;
import robocode.BulletMissedEvent;
import robocode.BulletHitEvent;
import robocode.HitWallEvent;
import robocode.Robot;
import robocode.ScannedRobotEvent;

/**
 * A robot that tries to kill as many enemies and dodge as many bullets as possible.
 * 
 * @author Chuan Lun Hung
 * 
 */
public class Chuan extends Robot {

  // turns stores the number of turns
  private int turns = 0;
  // numBulletMissed stores the number of bullets missed in a row
  private int numBulletsMissed = 0;
  // number of times this robot hit a wall
  private int numHitWall = 0;

  /**
   * The main method for robot's functionality.
   */
  public void run() {
    // change this robot's color to white
    setBodyColor(Color.white);
    setGunColor(Color.white);
    setRadarColor(Color.white);
    // set the gun so it doesn't turn when this robot is turning
    setAdjustGunForRobotTurn(true);
    while (true) {
      // look for a possible enemy every 10 turns
      if (turns % 10 == 0) {
        turnRadarRight(360);
      }
      turns++;
    }
  }

  /**
   * onScannedRobot method determines the actions of this robot when a target is found.
   * 
   * @param event (ScannedRobotEvent)
   */
  public void onScannedRobot(ScannedRobotEvent event) {

    // set enemyAngle to the angle relative to the battle field
    double enemyAngle = (getHeading() + event.getBearing()) % 360;
    // store enemy's bearing
    // enemyBearing = event.getBearing();
    lockOnTarget(enemyAngle);
    fire(getBulletPower(numBulletsMissed));
    // enemyBearing = enemyAngle;

    // if this robot is stuck in any corner, move forward 300 pixels
    if ((getBattleFieldWidth() - getX() < 100 && getY() < 100)
        || (getBattleFieldWidth() - getX() < 100 && getBattleFieldHeight() - getY() < 100)
        || (getX() < 100 && getBattleFieldHeight() - getY() < 100)
        || (getX() < 100 && getY() < 100)) {
      turnRight(event.getBearing());
      ahead(100);
    }
    // else keep moving right or left, depending on the sign of dodgeDistance
    else {
      turnRight(event.getBearing() - 90);
      ahead(moveDistance(numHitWall));
    }
  }

  /**
   * 
   * @param numWallHits int - number of times the robot hit a wall
   * @return double - distance to move
   */
  public static double moveDistance(int numWallHits) {
    int direction = numWallHits % 2;
    if (direction == 0) {
      return 80;
    }
    else {
      return -80;
    }
  }

  /**
   * lockOnTarget allows this robot's gun to point at its target the whole time, and then fires
   * after the target is locked on.
   * 
   * @param enemyAngle (double)
   */
  public void lockOnTarget(double enemyAngle) {
    // determine the angle between robot's gun and the enemy relative to the map,
    // turn the gun left or right depending on the enemy's location, and fire
    if (getGunHeading() > enemyAngle) {
      if (getGunHeading() - enemyAngle > 180) {
        turnGunRight(360 - getGunHeading() + enemyAngle);
        fire(getBulletPower(numBulletsMissed));
      }
      else {
        turnGunLeft(getGunHeading() - enemyAngle);
        fire(getBulletPower(numBulletsMissed));
      }
    }
    else {
      if (enemyAngle - getGunHeading() > 180) {
        turnGunLeft(360 + getGunHeading() - enemyAngle);
        fire(getBulletPower(numBulletsMissed));
      }
      else {
        turnGunRight(enemyAngle - getGunHeading());
        fire(getBulletPower(numBulletsMissed));
      }
    }
  }

  /**
   * bulletPower returns the power of the bullet depending on the number of bullets missed
   * consecutively.
   * @param numHitMissed The number of bullets missed.
   * @return 1, 2, or 3 based on the number of missed bullets
   */
  public static double getBulletPower(int numHitMissed) {
    if (numHitMissed == 0) {
      return 3;
    }
    if (numHitMissed == 1) {
      return 2;
    }
    else {
      return 1;
    }
  }

  /**
   * onBulletMissed increments numBulletMissed each time the bullet misses its target. This robot's
   * fire power changes according to the value of numBulletMissed
   * 
   * @param event (BulletMissedEvent)
   */
  public void onBulletMissed(BulletMissedEvent event) {
    numBulletsMissed++;
  }

  /**
   * onBulletHit resets numBulletMissed to zero. This robot's fire power changes according to the
   * value of numBulletMissed.
   * 
   * @param event (BulletHitEvent)
   */
  public void onBulletHit(BulletHitEvent event) {
    numBulletsMissed = 0;
  }

  /**
   * onHitWall increments numHitWall which can determine which direction to move.
   * 
   * @param event (HitWallEvent)
   */
  public void onHitWall(HitWallEvent event) {
    numHitWall++;
  }

}
